Provide xend support for setting up TPM front- and back-end interfaces.
authorshand@ubuntu.eng.hq.xensource.com <shand@ubuntu.eng.hq.xensource.com>
Tue, 30 Aug 2005 19:28:26 +0000 (11:28 -0800)
committershand@ubuntu.eng.hq.xensource.com <shand@ubuntu.eng.hq.xensource.com>
Tue, 30 Aug 2005 19:28:26 +0000 (11:28 -0800)
Signed-off-by: Steven Hand <steven@xensource.com>
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
tools/examples/xmexample1
tools/examples/xmexample2
tools/examples/xmexample3
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/image.py
tools/python/xen/xend/server/tpmif.py [new file with mode: 0644]
tools/python/xen/xm/create.py

index a5cf683c5bdc93e740349240977655f1fd89cba9..b3aecf854e8167929dbdcbb2c704e52c80a8c999 100644 (file)
@@ -47,6 +47,20 @@ name = "ExampleDomain"
 
 disk = [ 'phy:hda1,hda1,w' ]
 
+#----------------------------------------------------------------------------
+# Define to which TPM instance the user domain should communicate.
+# The vtpm entry is of the form 'instance=INSTANCE,backend=DOM'
+# where INSTANCE indicates the instance number of the TPM the VM
+# should be talking to and DOM provides the domain where the backend
+# is located.
+# Note that no two virtual machines should try to connect to the same
+# TPM instance. The handling of all TPM instances does require
+# some management effort in so far that VM configration files (and thus
+# a VM) should be associated with a TPM instance throughout the lifetime
+# of the VM / VM configuration file. The instance number must be
+# greater or equal to 1.
+#vtpm = [ 'instance=1,backend=0' ]
+
 #----------------------------------------------------------------------------
 # Set the kernel command line for the new domain.
 # You only need to define the IP parameters and hostname if the domain's
index ea349cfa6703e6192a56f6c67fc938f65f2e2471..0acf32bbeccd800cf107681fc3359c1089fe5d9f 100644 (file)
@@ -83,6 +83,20 @@ vcpus = 4 # make your domain a 4-way
 disk = [ 'phy:sda%d,sda1,w' % (7+vmid),
          'phy:sda6,sda6,r' ]
 
+#----------------------------------------------------------------------------
+# Define to which TPM instance the user domain should communicate.
+# The vtpm entry is of the form 'instance=INSTANCE,backend=DOM'
+# where INSTANCE indicates the instance number of the TPM the VM
+# should be talking to and DOM provides the domain where the backend
+# is located.
+# Note that no two virtual machines should try to connect to the same
+# TPM instance. The handling of all TPM instances does require
+# some management effort in so far that VM configration files (and thus
+# a VM) should be associated with a TPM instance throughout the lifetime
+# of the VM / VM configuration file. The instance number must be
+# greater or equal to 1.
+#vtpm = ['instance=%d,backend=0' % (vmid) ]
+
 #----------------------------------------------------------------------------
 # Set the kernel command line for the new domain.
 # You only need to define the IP parameters and hostname if the domain's
index fd96a7b201a382df083928a1924ee857014f92e2..1fa80cb2e3b036689b19958192c7a3cf0304bc99 100644 (file)
@@ -79,6 +79,20 @@ vif = [ 'ip=192.168.%d.1/24' % (vmid)]
 # All domains get sda6 read-only (to use for /usr, see below).
 disk = [ 'phy:hda%d,hda1,w' % (vmid)]
 
+#----------------------------------------------------------------------------
+# Define to which TPM instance the user domain should communicate.
+# The vtpm entry is of the form 'instance=INSTANCE,backend=DOM'
+# where INSTANCE indicates the instance number of the TPM the VM
+# should be talking to and DOM provides the domain where the backend
+# is located.
+# Note that no two virtual machines should try to connect to the same
+# TPM instance. The handling of all TPM instances does require
+# some management effort in so far that VM configration files (and thus
+# a VM) should be associated with a TPM instance throughout the lifetime
+# of the VM / VM configuration file. The instance number must be
+# greater or equal to 1.
+#vtpm = ['instance=%d,backend=0' % (vmid) ]
+
 #----------------------------------------------------------------------------
 # Set the kernel command line for the new domain.
 # You only need to define the IP parameters and hostname if the domain's
index 7ee3930fd84f8711eba96a379b79bd854357bfc9..be1e630cdb15f12c58a1d55a1963ac87678e7363 100644 (file)
@@ -269,6 +269,7 @@ class XendDomainInfo:
         self.blkif_backend = False
         self.netif_backend = False
         self.netif_idx = 0
+        self.tpmif_backend = False
         
         #todo: state: running, suspended
         self.state = STATE_VM_OK
@@ -458,6 +459,31 @@ class XendDomainInfo:
 
             return
         
+        if type == 'vtpm':
+            backdom = domain_exists(sxp.child_value(devconfig, 'backend', '0'))
+
+            devnum = int(sxp.child_value(devconfig, 'instance', '0'))
+            log.error("The domain has a TPM with instance %d." % devnum)
+
+            # create backend db
+            backdb = backdom.db.addChild("/backend/%s/%s/%d" %
+                                         (type, self.uuid, devnum))
+            # create frontend db
+            db = self.db.addChild("/device/%s/%d" % (type, devnum))
+
+            backdb['frontend'] = db.getPath()
+            backdb['frontend-id'] = "%i" % self.id
+            backdb['instance'] = sxp.child_value(devconfig, 'instance', '0')
+            backdb.saveDB(save=True)
+
+            db['handle'] = "%i" % devnum
+            db['backend'] = backdb.getPath()
+            db['backend-id'] = "%i" % int(sxp.child_value(devconfig,
+                                                          'backend', '0'))
+            db.saveDB(save=True)
+
+            return
+
         ctrl = self.findDeviceController(type)
         return ctrl.createDevice(devconfig, recreate=self.recreate,
                                  change=change)
@@ -779,6 +805,11 @@ class XendDomainInfo:
                 for dev in typedb.keys():
                     typedb[dev].delete()
                 typedb.saveDB(save=True)
+            if type == 'vtpm':
+                typedb = ddb.addChild(type)
+                for dev in typedb.keys():
+                    typedb[dev].delete()
+                typedb.saveDB(save=True)
 
     def show(self):
         """Print virtual machine info.
@@ -1018,6 +1049,8 @@ class XendDomainInfo:
                 self.netif_backend = True
             elif name == 'usbif':
                 self.usbif_backend = True
+            elif name == 'tpmif':
+                self.tpmif_backend = True
             else:
                 raise VmError('invalid backend type:' + str(name))
 
@@ -1190,6 +1223,10 @@ from server import netif
 controller.addDevControllerClass("vif", netif.NetifController)
 add_device_handler("vif", "vif")
 
+from server import tpmif
+controller.addDevControllerClass("vtpm", tpmif.TPMifController)
+add_device_handler("vtpm", "vtpm")
+
 from server import pciif
 controller.addDevControllerClass("pci", pciif.PciController)
 add_device_handler("pci", "pci")
index 8e9f5fa0a6396fb83c8d8bf3e37f26804bcf27be..09b6b9fc47ef259d27dc6854b3648f37e1d3e567 100644 (file)
@@ -32,6 +32,9 @@ SIF_BLK_BE_DOMAIN = (1<<4)
 """Flag for a net device backend domain."""
 SIF_NET_BE_DOMAIN = (1<<5)
 
+"""Flag for a TPM device backend domain."""
+SIF_TPM_BE_DOMAIN = (1<<7)
+
 class ImageHandler:
     """Abstract base class for image handlers.
 
@@ -194,6 +197,7 @@ class ImageHandler:
         self.flags = 0
         if self.vm.netif_backend: self.flags |= SIF_NET_BE_DOMAIN
         if self.vm.blkif_backend: self.flags |= SIF_BLK_BE_DOMAIN
+        if self.vm.tpmif_backend: self.flags |= SIF_TPM_BE_DOMAIN
 
         if self.vm.recreate or self.vm.restore:
             return
@@ -366,6 +370,11 @@ class VmxImageHandler(ImageHandler):
                mac = sxp.child_value(vifinfo, 'mac')
                ret.append("-macaddr")
                ret.append("%s" % mac)
+            if name == 'vtpm':
+               vtpminfo = sxp.child(device, 'vtpm')
+               instance = sxp.child_value(vtpminfo, 'instance')
+               ret.append("-instance")
+               ret.append("%s" % instance)
 
        # Handle graphics library related options
        vnc = sxp.child_value(self.vm.config, 'vnc')
diff --git a/tools/python/xen/xend/server/tpmif.py b/tools/python/xen/xend/server/tpmif.py
new file mode 100644 (file)
index 0000000..59e4202
--- /dev/null
@@ -0,0 +1,52 @@
+# Copyright (C) 2005 IBM Corporation
+#   Authort: Stefan Berger, stefanb@us.ibm.com
+# Derived from netif.py:
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Support for virtual TPM interfaces.
+"""
+
+import random
+
+from xen.xend import sxp
+from xen.xend.XendError import XendError, VmError
+from xen.xend.XendLogging import log
+from xen.xend.XendRoot import get_component
+from xen.xend.xenstore import DBVar
+
+from xen.xend.server import channel
+from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
+from xen.xend.server.messages import *
+
+class TPMifController(DevController):
+    """TPM interface controller. Handles all TPM devices for a domain.
+    """
+
+    def __init__(self, vm, recreate=False):
+        DevController.__init__(self, vm, recreate=recreate)
+        self.rcvr = None
+        self.channel = None
+
+    def initController(self, recreate=False, reboot=False):
+        self.destroyed = False
+        self.channel = self.getChannel()
+
+    def destroyController(self, reboot=False):
+        """Destroy the controller and all devices.
+        """
+        self.destroyed = True
+        self.destroyDevices(reboot=reboot)
+        if self.rcvr:
+            self.rcvr.deregisterChannel()
+
+    def sxpr(self):
+        val = ['tpmif', ['dom', self.getDomain()]]
+        return val
+
+    def newDevice(self, id, config, recreate=False):
+        """Create a TPM device.
+
+        @param id: interface id
+        @param config: device configuration
+        @param recreate: recreate flag (true after xend restart)
+        """
+        return None
index ec4ab49c123cdc33576bafb37ed39f580ff9e82f..dbf1dd116c8748bacbc5a39ff97913b901047b81 100644 (file)
@@ -175,6 +175,12 @@ gopts.var('netif', val='no|yes',
           fn=set_bool, default=0,
           use="Make the domain a network interface backend.")
 
+gopts.var('tpmif', val='frontend=DOM',
+          fn=append_value, default=[],
+          use="""Make the domain a TPM interface backend. If frontend is given,
+          the frontend in that domain is connected to this backend (not
+          completely implemented, yet)""")
+
 gopts.var('disk', val='phy:DEV,VDEV,MODE[,DOM]',
           fn=append_value, default=[],
           use="""Add a disk device to a domain. The physical device is DEV,
@@ -213,6 +219,12 @@ gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM
           This option may be repeated to add more than one vif.
           Specifying vifs will increase the number of interfaces as needed.""")
 
+gopts.var('vtpm', val="instance=INSTANCE,backend=DOM",
+          fn=append_value, default=[],
+          use="""Add a tpm interface. On the backend side us the the given
+          instance as virtual TPM instance. Use the backend in the given
+          domain.""")
+
 gopts.var('nics', val="NUM",
           fn=set_int, default=1,
           use="""Set the number of network interfaces.
@@ -369,6 +381,46 @@ def configure_usb(opts, config_devs, vals):
         config_usb = ['usb', ['path', path]]
         config_devs.append(['device', config_usb])
 
+def configure_vtpm(opts, config_devs, vals):
+    """Create the config for virtual TPM interfaces.
+    """
+    vtpm = vals.vtpm
+    vtpm_n = 1
+    for idx in range(0, vtpm_n):
+        if idx < len(vtpm):
+            d = vtpm[idx]
+            instance = d.get('instance')
+            if instance == "VTPMD":
+                instance = "0"
+            else:
+                try:
+                    if int(instance) == 0:
+                        opts.err('VM config error: vTPM instance must not be 0.')
+                except ValueError:
+                    opts.err('Vm config error: could not parse instance number.')
+            backend = d.get('backend')
+            config_vtpm = ['vtpm']
+            if instance:
+                config_vtpm.append(['instance', instance])
+            if backend:
+                config_vtpm.append(['backend', backend])
+            config_devs.append(['device', config_vtpm])
+
+def configure_tpmif(opts, config_devs, vals):
+    """Create the config for virtual TPM interfaces.
+    """
+    tpmif = vals.tpmif
+    tpmif_n = 1
+    for idx in range(0, tpmif_n):
+        if idx < len(tpmif):
+            d = tpmif[idx]
+            frontend = d.get('frontend')
+            config_tpmif = ['tpmif']
+            if frontend:
+                config_tpmif.append(['frontend', frontend])
+            config_devs.append(['device', config_tpmif])
+
+
 def randomMAC():
     """Generate a random MAC address.
 
@@ -479,6 +531,8 @@ def make_config(opts, vals):
         config.append(['backend', ['blkif']])
     if vals.netif:
         config.append(['backend', ['netif']])
+    if vals.tpmif:
+        config.append(['backend', ['tpmif']])
     if vals.restart:
         config.append(['restart', vals.restart])
 
@@ -491,6 +545,7 @@ def make_config(opts, vals):
     configure_pci(opts, config_devs, vals)
     configure_vifs(opts, config_devs, vals)
     configure_usb(opts, config_devs, vals)
+    configure_vtpm(opts, config_devs, vals)
     configure_vmx(opts, config_devs, vals)
     config += config_devs
 
@@ -539,6 +594,38 @@ def preprocess_vifs(opts, vals):
         vifs.append(d)
     vals.vif = vifs
 
+def preprocess_vtpm(opts, vals):
+    if not vals.vtpm: return
+    vtpms = []
+    for vtpm in vals.vtpm:
+        d = {}
+        a = vtpm.split(',')
+        for b in a:
+            (k, v) = b.strip().split('=', 1)
+            k = k.strip()
+            v = v.strip()
+            if k not in ['backend', 'instance']:
+                opts.err('Invalid vtpm specifier: ' + vtpm)
+            d[k] = v
+        vtpms.append(d)
+    vals.vtpm = vtpms
+
+def preprocess_tpmif(opts, vals):
+    if not vals.tpmif: return
+    tpmifs = []
+    for tpmif in vals.tpmif:
+        d = {}
+        a = tpmif.split(',')
+        for b in a:
+            (k, v) = b.strip().split('=', 1)
+            k = k.strip()
+            v = v.strip()
+            if k not in ['frontend']:
+                opts.err('Invalid tpmif specifier: ' + vtpm)
+            d[k] = v
+        tpmifs.append(d)
+    vals.tpmif = tpmifs
+
 def preprocess_ip(opts, vals):
     if vals.ip or vals.dhcp != 'off':
         dummy_nfs_server = '1.2.3.4'
@@ -627,6 +714,8 @@ def preprocess(opts, vals):
     preprocess_ip(opts, vals)
     preprocess_nfs(opts, vals)
     preprocess_vnc(opts, vals)
+    preprocess_vtpm(opts, vals)
+    preprocess_tpmif(opts, vals)
          
 def make_domain(opts, config):
     """Create, build and start a domain.